package org.example;

import java.net.MalformedURLException;
import java.net.URL;

import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.TreeMap;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;

public class LinkList implements AutoCloseable {
    private static final int CONNECTION_DELAY_MIN = 100;    // ms
    private static final int CONNECTION_DELAY_MAX = 150;    // ms

    private final URL root;
    private final String domain;

    private final Map<String, URL> list = new TreeMap<>();
    private final ForkJoinPool tasksPool = new ForkJoinPool();

    public LinkList(String link) throws MalformedURLException {
        this(link, -1);
    }

    // deepLimit: 0 - root only, <0 - no limit
    public LinkList(String link, int deepLimit) throws MalformedURLException {
        root = new URL(link
                .replaceAll("#.*", "")
                .replaceAll("/+$", "")
        );
        domain = root.getHost().toLowerCase();

        tasksPool.invoke(new LinkTask(this, root, deepLimit));
        System.out.println();
    }

    public URL getRootURL() {
        return root;
    }

    public boolean isRootDomain(URL url) {
        if (url == null) {
            return false;
        }

        return isRootDomain(url.getHost());
    }

    public boolean isRootDomain(String domain) {
        return this.domain.equals(domain.toLowerCase());
    }

    public boolean add(URL url) {
        if (tasksPool.isShutdown()) {
            return false;
        }

        String file = url.getFile().toLowerCase();

        synchronized (list) {
            if (!list.containsKey(file)) {
                list.put(file, url);
                return true;
            }
        }

        return false;
    }

    public void remove(URL url) {
        String file = url.getFile().toLowerCase();

        synchronized (list) {
            if (list.containsKey(file)) {
                list.put(file, null);
            }
        }
    }

    public synchronized void connectionDelay() {
        if (tasksPool.isShutdown()) {
            return;
        }

        try {
            Thread.sleep((long) (
                    Math.random() * (CONNECTION_DELAY_MAX - CONNECTION_DELAY_MIN)
                            + CONNECTION_DELAY_MIN
            ));
        } catch (InterruptedException ignored) {}
    }

    @Override
    public void close() throws Exception {
        tasksPool.shutdown();
        tasksPool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
    }

    public String toString() {
        StringJoiner joiner = new StringJoiner(System.lineSeparator());

        list.values().stream()
                .filter(Objects::nonNull)
                .map(url -> url.getPath()
                        .replaceAll("[^/]", "")
                        .replace("/", "\t")
                        + url
                )
                .forEach(joiner::add);

        return joiner.toString();
    }
}
